import datetime
import json
import logging
import re
import time
import uuid
from decimal import Decimal
from urllib import parse

import pymongo
import requests
import xmltodict
from tornado import httpclient
from tornado.escape import json_encode
from tornado.httpclient import HTTPRequest
from tornado.httputil import url_concat

from base.connection import mongodb_util, redis_util
from base.request import BaseHandler
from common.definition import (
    BenefitType,
    OrderStatus,
    OrderType,
    PayStatus,
    PayType,
    ret_msg,
)
from conf import config
from conf.config import (
    CANCEL_PAID_ORDER_IS_NEED_CHECK,
    DAYS_AFTER_RECEIVED_FOR_AUTO_COMPLETION,
    DAYS_AFTER_SHIPPED_FOR_AUTO_COMPLETION,
    DEFAULT_AGENCY_UID,
    FACTORY_ID,
    FACTORY_UID,
    GIFT_ORDER_REFUND_TIMEOUT,
    MP_APP_ID,
    KUAIDI100_CUSTOMER,
)
from daemon import tasks
from helper.beanstalkd import add_mq_task
from helper.exceptions import ShareNotOwnerException
from helper.express_helper import ExpressHelper
from helper.gift import GiftHelper
from helper.payment.balance import (
    BalanceHandler,
    create_balance_record,
    update_account_money,
)
from helper.payment.pay_util import (
    AgencyType,
    calculate_order_fee,
    generator_trade_no,
    create_order,
    handle_agency_register_order,
)
from helper.payment.refund import (
    CancelOrderRefund,
    cancel_order_immediate_refund,
    order_refund,
)
from helper.payment.wechat_base import Wechat_Base
from helper.payment.wechat_pay import WechatPay, weixin_verify
from helper.payment.weixin_xml import wechat_resp
from helper.service.notify import invoke_push_topic
from helper.user import AddressHelper, UserHelper
from util.json_util import JSONEncoder

logger = logging.getLogger("wechat.handlers.mall")


class Mall(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        open_id = await self.get_open_id()
        is_pad = True if re.match(r"^\d+$", open_id) else False

        # 启用新版微信商城 20180919
        if not is_pad:
            return self.redirect("/static/app1/index.html#/mall")

        class Goods(object):
            pass

        class Carts(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_cart", "model": Carts},
            ]
        )
        goods_array = (
            session.query(Goods)
            .filter_by(
                sdef_goods_status=1,
                sdef_goods_is_delete=0,
                sdef_goods_factory_uid=FACTORY_UID,
            )
            .order_by(Goods.sdef_goods_order_num.asc(), Goods.sdef_goods_price.asc())
            .all()
        )
        cart_array = session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()

        cart_count = 0
        if len(cart_array) > 0:
            cart_goods = json.loads(cart_array[0].sdef_cart_goods)
            for g in cart_goods:
                cart_count = cart_count + g["count"]

        context = dict(
            text="商城",
            goods_array=goods_array,
            cart_count=cart_count,
            device_id=open_id,
            is_membership=self.is_membership(open_id),
        )

        # 微信分享功能
        is_wechat = self.is_in_wechat()
        if is_wechat:
            # 绑定用户的合伙人和推荐人
            await self.bind_user(open_id)

            app_id = MP_APP_ID
            time_stamp = int(str(time.time()).split(".")[0])
            nonce_str = WechatPay.generate_nonce_str()

            host = self.request.host
            url_params = self.request.query
            request_path = self.request.path
            protocol = self.request.protocol
            full_url = protocol + "://" + host + request_path
            if url_params:
                full_url += "?" + url_params

            jsapi_ticket = self.get_jsapi_ticket()
            signature = Wechat_Base.signature(
                nonce_str, time_stamp, full_url, jsapi_ticket
            )
            logging.debug("signature：%s" % signature)
            context["app_id"] = app_id
            context["time_stamp"] = time_stamp
            context["nonce_str"] = nonce_str
            context["signature"] = signature
            context["is_wechat"] = is_wechat

        template = "pad_mall/mall.html" if is_pad else "mall/mall.html"
        return self.render_html(template, **context)

    async def post(self):
        open_id = await self.get_open_id()

        action = self.get_argument("action")
        if action == "add-cart":
            goods_id = self.get_argument("goods_id")
            count = self.get_argument("count", None)
            if count is None:
                count = 1
            count = int(count)

            # 没加入会员时只能买酒柜
            # device_id = self.get_argument("device_id", "")

            # 在屏端购买的已经是会员了，不需要限制
            # 非会员允许买酒了
            # if device_id != open_id:
            #     if goods_id != config.MEMBERSHIP_GOODS_ID and not self.is_membership(open_id):
            #         return self.write(ret_msg(3))

            if not (goods_id and re.match("^\d+$", goods_id)):
                return self.write(ret_msg(-1, error_message="商品编号错误"))

            class Carts(object):
                pass

            class Goods(object):
                pass

            session = self.get_db_session(
                [
                    {"db_table": "sdet_cart", "model": Carts},
                    {"db_table": "sdet_goods", "model": Goods},
                ]
            )

            # 检查库存：必须是上架+未删除+库存大于0
            _filter = dict(
                sdef_goods_id=goods_id, sdef_goods_status=1, sdef_goods_is_delete=0
            )
            goods = (
                session.query(Goods)
                .filter(Goods.sdef_goods_count > 0)
                .filter_by(**_filter)
                .first()
            )
            if not goods:
                return self.write(ret_msg(-1, error_message="商品库存不足或已下架"))

            # 检查数量是否超出库存
            if count > goods.sdef_goods_count:
                return self.write(ret_msg(-1, error_message="商品库存不足"))

            cart = session.query(Carts).filter_by(sdef_cart_device_id=open_id).first()
            cart_goods = []
            is_exists = False
            if cart:
                is_exists = True
                cart_goods = json.loads(cart.sdef_cart_goods)

                # 检查购物车是否已经有这个商品
                for c in cart_goods:
                    if c.get("id") == goods_id:
                        c["count"] += count
                        if c["count"] > goods.sdef_goods_count:
                            return self.write(ret_msg(-1, error_message="商品库存不足"))
                        # 修改
                        cart_goods_json = json.dumps(cart_goods)
                        session.query(Carts).filter_by(
                            sdef_cart_device_id=open_id
                        ).update({Carts.sdef_cart_goods: cart_goods_json})
                        session.commit()
                        # 计算购物车商品数量
                        cart_count = 0
                        for c in cart_goods:
                            cart_count += c["count"]
                        return self.write(ret_msg(data=cart_count))

            # 新商品添加进购物车
            cart_goods.append({"id": goods_id, "count": count})
            cart_goods_json = json.dumps(cart_goods)
            if is_exists:
                # 修改
                session.query(Carts).filter_by(sdef_cart_device_id=open_id).update(
                    {Carts.sdef_cart_goods: cart_goods_json}
                )
                session.commit()
            else:
                # 添加购物车
                _cart = Carts()
                _cart.sdef_cart_device_id = open_id
                _cart.sdef_cart_goods = cart_goods_json
                _cart.sdef_cart_update_time = datetime.datetime.now()
                session.add(_cart)
                session.commit()
        # 计算购物车商品数量
        cart_count = 0
        for c in cart_goods:
            cart_count += c["count"]
        return self.write(ret_msg(data=cart_count))


class Cart(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        open_id = await self.get_open_id()
        is_pad = True if re.match(r"^\d+$", open_id) else False
        is_membership = self.is_membership(open_id)
        logger.debug("是否为会员，open_id=%s,is_membership=%s" % (open_id, is_membership))

        class Goods(object):
            pass

        class Carts(object):
            pass

        class UserAddress(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_cart", "model": Carts},
                {"db_table": "sdet_address", "model": UserAddress},
            ]
        )
        cart_array = session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()
        cart_goods_array = []
        cart_goods = []
        price_total = Decimal(0)
        if len(cart_array) > 0:
            cart_goods = json.loads(cart_array[0].sdef_cart_goods)

        for c in cart_goods:
            goods_id = c["id"]
            count = c["count"]
            _goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).one()
            goods_price = (
                _goods.sdef_goods_member_price
                if is_membership
                else _goods.sdef_goods_price
            )
            goods = dict(
                id=goods_id,
                count=count,
                goods_img=json.loads(_goods.sdef_goods_thumbnail)[0],
                goods_name=_goods.sdef_goods_name,
                goods_price=goods_price,
            )
            price_total += goods_price * Decimal(count)
            cart_goods_array.append(goods)

        default_address = AddressHelper.get_default(open_id)
        if default_address:
            logger.debug("默认地址，address_id=%s" % default_address["address_id"])
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=default_address["address_id"])
                .first()
            )
        else:
            # 尝试获取第一个地址
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_device_id=open_id, sdef_address_is_del=0)
                .order_by(UserAddress.sdef_address_id.desc())
                .first()
            )

        context = dict(
            text="购物车",
            cart_goods_array=cart_goods_array,
            price_total=price_total,
            address=address,
            open_id=open_id,
            device_id=open_id,
        )
        # session.close()
        template = "pad_mall/cart.html" if is_pad else "mall/cart.html"
        return self.render_html(template, **context)

    async def post(self):
        open_id = await self.get_open_id()

        action = self.get_argument("action")

        class Carts(object):
            pass

        class Goods(object):
            pass

        if action == "mod-cart-count":
            goods_id = self.get_argument("goods_id")
            count = int(self.get_argument("count"))
            if count <= 0:
                return self.write(ret_msg(-1, error_message="商品数量必须大于等于0"))

            session = self.get_db_session(
                [
                    {"db_table": "sdet_cart", "model": Carts},
                    {"db_table": "sdet_goods", "model": Goods},
                ]
            )

            # 检查库存：必须是上架+未删除+库存大于0
            _filter = dict(
                sdef_goods_id=goods_id, sdef_goods_status=1, sdef_goods_is_delete=0
            )
            goods = (
                session.query(Goods)
                .filter(Goods.sdef_goods_count > 0)
                .filter_by(**_filter)
                .first()
            )
            if not goods:
                return self.write(ret_msg(-1, error_message="商品库存不足或已下架"))

            # 检查数量是否超出库存
            if count > goods.sdef_goods_count:
                return self.write(ret_msg(-1, error_message="商品库存不足"))

            cart_array = (
                session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()
            )
            if len(cart_array) > 0:
                cart_goods = json.loads(cart_array[0].sdef_cart_goods)
            else:
                cart_goods = []

            for c in cart_goods:
                if c.get("id") == goods_id:
                    c["count"] = int(count)
                    session.query(Carts).filter_by(sdef_cart_device_id=open_id).update(
                        {Carts.sdef_cart_goods: json.dumps(cart_goods)}
                    )
                    # 提交
                    session.commit()
                    # 计算购物车商品数量
                    cart_count = 0
                    for c1 in cart_goods:
                        cart_count += c1["count"]
                    return self.write(ret_msg(data=cart_count))
            return self.write(ret_msg(-1, error_message="购物车不存在此商品"))
        if action == "del-cart-goods":
            goods_id = self.get_argument("goods_id")

            session = self.get_db_session(
                [
                    {"db_table": "sdet_cart", "model": Carts},
                ]
            )

            cart_array = (
                session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()
            )
            if len(cart_array) > 0:
                cart_goods = json.loads(cart_array[0].sdef_cart_goods)
            else:
                cart_goods = []

            cart_goods_new = []
            for c in cart_goods:
                if c.get("id") == goods_id:
                    continue
                cart_goods_new.append(c)
            session.query(Carts).filter_by(sdef_cart_device_id=open_id).update(
                {Carts.sdef_cart_goods: json.dumps(cart_goods_new)}
            )
            # session.flush()
            session.commit()
            return self.write(ret_msg())
        return self.write(ret_msg())


class GoodsDetail(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self, goods_id):
        view = self.get_argument("view", None)
        if view:
            logger.debug("查看者" + view)
            ret = None
        else:
            ret = await self.get_open_id()

        open_id = ret
        if open_id:
            is_pad = True if re.match(r"^\d+$", open_id) else False
        else:
            is_pad = True

        class Goods(object):
            pass

        class UserAddress(object):
            pass

        class Carts(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_address", "model": UserAddress},
                {"db_table": "sdet_cart", "model": Carts},
            ]
        )
        _goods = session.query(Goods).filter_by(sdef_goods_id=goods_id).all()[0]

        cart_array = session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()

        cart_count = 0
        if len(cart_array) > 0:
            cart_goods = json.loads(cart_array[0].sdef_cart_goods)
            for g in cart_goods:
                cart_count = cart_count + g["count"]

        default_address = AddressHelper.get_default(open_id)
        use_address = AddressHelper.get_use(open_id)
        db = mongodb_util.db
        address = None
        if use_address:
            logger.debug("使用地址，address_id=%s" % use_address["address_id"])
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=use_address["address_id"])
                .first()
            )
        elif default_address:
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=default_address["address_id"])
                .first()
            )
        else:
            # 尝试获取第一个地址
            # address = session.query(UserAddress).filter_by(sdef_address_device_id=open_id,
            #                                                sdef_address_is_del=0).order_by(
            #     UserAddress.sdef_address_id.desc()).first()

            result = db.sdec_address.find(
                {"user_id": open_id, "is_delete": False}
            ).sort("update_time", pymongo.DESCENDING)
            for a in result:
                address = (
                    session.query(UserAddress)
                    .filter_by(sdef_address_id=a["address_id"])
                    .first()
                )
                break

            # 如果酒柜没有设置地址，就取主人手机设置的地址
            if (not address) and is_pad:
                master_open_id = self.get_device_master_open_id(open_id)
                if master_open_id:
                    default_address = AddressHelper.get_default(master_open_id)
                    if default_address:
                        address = (
                            session.query(UserAddress)
                            .filter_by(sdef_address_id=default_address["address_id"])
                            .first()
                        )
                    else:
                        # 尝试获取第一个地址
                        address = (
                            session.query(UserAddress)
                            .filter_by(
                                sdef_address_device_id=master_open_id,
                                sdef_address_is_del=0,
                            )
                            .order_by(UserAddress.sdef_address_id.desc())
                            .first()
                        )

                    if address:
                        AddressHelper.add(
                            open_id,
                            address.sdef_address_name,
                            address.sdef_address_phone,
                            address.sdef_address_province,
                            address.sdef_address_city,
                            address.sdef_address_county,
                            address.sdef_address_detail,
                            address.sdef_address_id,
                            is_default=True,
                        )

        source = self.get_argument("source", None)
        is_wechat = self.is_in_wechat()
        context = dict(
            text="商品详情",
            goods=_goods,
            goods_imgs=json.loads(_goods.sdef_goods_img),
            address=address,
            membership_goods_id=config.MEMBERSHIP_GOODS_ID,
            is_membership=self.is_membership(open_id),
            open_id=open_id,
            device_id=open_id,
            cart_count=cart_count,
            view=view,
            source=source,
            is_wechat=is_wechat,
        )

        if is_wechat:
            # 绑定用户的合伙人和推荐人
            await self.bind_user(open_id)

            app_id = MP_APP_ID
            time_stamp = int(str(time.time()).split(".")[0])
            nonce_str = WechatPay.generate_nonce_str()

            host = self.request.host
            url_params = self.request.query
            request_path = self.request.path
            protocol = self.request.protocol
            full_url = protocol + "://" + host + request_path
            if url_params:
                full_url += "?" + url_params

            jsapi_ticket = self.get_jsapi_ticket()
            signature = Wechat_Base.signature(
                nonce_str, time_stamp, full_url, jsapi_ticket
            )
            logging.debug("signature：%s" % signature)
            context["app_id"] = app_id
            context["time_stamp"] = time_stamp
            context["nonce_str"] = nonce_str
            context["signature"] = signature

        template = "pad_mall/goods-detail.html" if is_pad else "mall/goods-detail.html"
        # 屏端跳过商品详情页=>DS商品跳过详情页，直接扫二维码确认订单
        count = 1
        if is_pad and source == "ds":
            return self.redirect(
                "/pad/payment/confirm?device_id=%s&t=buy&id=%s&c=%s&source=%s"
                % (open_id, goods_id, count, source)
            )
        else:
            return self.render_html(template, **context)


class AddressManage(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        open_id = await self.get_open_id()

        class UserAddress(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_address", "model": UserAddress},
            ]
        )

        address_list = []
        # 从mongodb中获取地址列表
        db = mongodb_util.db
        address_count = db.sdec_address.find({"user_id": open_id}).count()
        logger.debug("address_count=%s" % address_count)
        if address_count == 0:
            # 尝试从mysql中获取
            _address = (
                session.query(UserAddress)
                .filter_by(sdef_address_device_id=open_id, sdef_address_is_del=0)
                .order_by(UserAddress.sdef_address_id.desc())
                .first()
            )
            if _address:
                data = AddressHelper.add(
                    open_id,
                    _address.sdef_address_name,
                    _address.sdef_address_phone,
                    _address.sdef_address_province,
                    _address.sdef_address_city,
                    _address.sdef_address_county,
                    _address.sdef_address_detail,
                    _address.sdef_address_id,
                )
                address_list.append(data)
        else:
            _filter = {"user_id": open_id, "is_delete": False}
            all_address = db.sdec_address.find(_filter).sort("_id", pymongo.DESCENDING)
            for a in all_address:
                address_list.append(a)

        # session.close()
        context = dict(
            is_wechat=self.is_in_wechat(),
            open_id=open_id,
            title="收货地址列表",
            address_list=address_list,
        )
        return self.render_html("mall/address_manage.html", **context)

    async def post(self):
        open_id = await self.get_open_id()

        action = self.get_argument("action", None)
        address_id = self.get_argument("address_id", None)

        if action == "delete":
            AddressHelper.delete(open_id, address_id)
            return self.write(ret_msg())
        elif action == "set-default":
            is_default = self.get_argument("is_default")
            is_default = True if is_default == "true" else False
            AddressHelper.set_default(open_id, address_id, is_default)
            return self.write(ret_msg())

        return self.write(ret_msg(-1))


class Address(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        open_id = await self.get_open_id()
        is_pad = True if re.match(r"^\d+$", open_id) else False

        class UserAddress(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_address", "model": UserAddress},
            ]
        )

        address = None
        address_id = self.get_argument("id", None)
        if address_id:
            filters = dict(
                sdef_address_id=address_id,
                sdef_address_is_del=0,
            )
            if is_pad:
                filters["sdef_address_device_id"] = open_id

            _address = (
                session.query(UserAddress)
                .filter_by(**filters)
                .order_by(UserAddress.sdef_address_id.desc())
                .first()
            )
            if _address:
                # 微信修改设备上的地址
                if re.match(r"^\d+$", _address.sdef_address_device_id):
                    address = _address
                elif _address.sdef_address_device_id == open_id:  # 避免其它人越权修改地址
                    address = _address

        context = dict(
            text="收货地址",
            address=address,
            open_id=open_id,
            device_id=open_id,
        )
        # session.close()
        template = "pad_mall/address.html" if is_pad else "mall/address.html"
        return self.render_html(template, **context)

    async def post(self):
        open_id = await self.get_open_id()

        action = self.get_argument("action")
        if action == "add-address":
            main_address = self.get_argument("mainAddress")
            name = self.get_argument("name")
            phone = self.get_argument("phone")
            address = self.get_argument("address")
            postal_code = self.get_argument("postalCode")
            code = self.get_argument("code", None)

            if not re.match(r"^1\d{10}$", phone):
                return self.write(ret_msg(-1, error_message="请输入正确的手机号"))

            main_address_list = main_address.split(" ")
            if len(main_address_list) != 3:
                return self.write(ret_msg(-1, error_message="省市区格式不正确"))

            class UserAddress(object):
                pass

            class GoodsOrder(object):
                pass

            if code:
                decrypt_order_id = GiftHelper.decrypt_order_id(code)
                check_ret = GiftHelper.check_order(decrypt_order_id)
                if check_ret.get("code") != 0:
                    return self.write(json.dumps(check_ret))

            session = self.get_db_session(
                [
                    {"db_table": "sdet_order", "model": GoodsOrder},
                    {"db_table": "sdet_address", "model": UserAddress},
                ]
            )
            _address = UserAddress()
            _address.sdef_address_phone = phone
            _address.sdef_address_name = name
            _address.sdef_address_postal_code = postal_code
            _address.sdef_address_detail = address
            # 支持礼物填写地址，填写完之后要更新订单中的地址
            if code:
                _address.sdef_address_device_id = decrypt_order_id
            else:
                _address.sdef_address_device_id = open_id

            address_id = self.get_argument("id", None)
            logger.info("address_id=%s" % address_id)
            if address_id:
                filters = dict(
                    sdef_address_id=address_id,
                    sdef_address_is_del=0,
                )
                address_old = session.query(UserAddress).filter_by(**filters).first()

                if address_old and re.match(
                    r"^\d+$", address_old.sdef_address_device_id
                ):
                    logger.info(
                        "修改设备上的地址：sdef_address_device_id=%s"
                        % address_old.sdef_address_device_id
                    )
                    _address.sdef_address_device_id = address_old.sdef_address_device_id

            _address.sdef_address_is_del = 0
            _address.sdef_address_province = main_address_list[0].strip()
            _address.sdef_address_city = main_address_list[1].strip()
            _address.sdef_address_county = main_address_list[2].strip()
            session.add(_address)
            # session.flush()
            session.commit()

            if address_id:
                new_address_id = _address.sdef_address_id
                AddressHelper.update(
                    open_id,
                    _address.sdef_address_name,
                    _address.sdef_address_phone,
                    _address.sdef_address_province,
                    _address.sdef_address_city,
                    _address.sdef_address_county,
                    _address.sdef_address_detail,
                    address_id,
                    is_default=None,
                    new_address_id=new_address_id,
                )
            else:
                AddressHelper.add(
                    open_id,
                    _address.sdef_address_name,
                    _address.sdef_address_phone,
                    _address.sdef_address_province,
                    _address.sdef_address_city,
                    _address.sdef_address_county,
                    _address.sdef_address_detail,
                    _address.sdef_address_id,
                    is_default=False,
                )

            if code:
                # 更新礼品订单地址
                update_fields = {
                    GoodsOrder.sdef_order_address_id: _address.sdef_address_id
                }
                session.query(GoodsOrder).filter_by(
                    sdef_order_id=decrypt_order_id
                ).update(update_fields)
                session.commit()
                # session.close()
        return self.write(ret_msg())


class PayConfirm(BaseHandler):
    """
    不与屏端的确认订单共用
    """

    async def get(self):
        open_id = await self.get_open_id()

        # device_id!=None 为设备下的订单
        device_id = self.get_argument("d", None)
        # t=buy表示立刻购买
        t = self.get_argument("t", None)
        type = self.get_argument("type", 0)

        is_membership = self.is_membership(open_id)

        class Goods(object):
            pass

        class GoodsOrder(object):
            pass

        class Carts(object):
            pass

        class UserAddress(object):
            pass

        class AccountMoney(object):
            pass

        class User(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_cart", "model": Carts},
                {"db_table": "sdet_address", "model": UserAddress},
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "ebt_account_money", "model": AccountMoney},
                {"db_table": "ebt_user", "model": User},
            ]
        )
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if user:
            nickname = user.ebf_user_nickname
            if nickname == "未关注" or nickname == "" or nickname is None:
                await self.update_nickname(open_id)

        cart_goods_array = []
        cart_goods = []
        price_total = Decimal(0)
        balance_fee = Decimal(0)

        if t == "buy":
            goods_id = self.get_argument("id")
            count = self.get_argument("c")
            cart_goods.append({"id": goods_id, "count": count})
            if device_id:
                invoke_push_topic(
                    device_id,
                    dict(
                        type=0,
                        message="已扫描，正在付款...",
                        data=None,
                    ),
                )
        elif t == "retry":
            # 继续支付
            old_order_id = self.get_argument("oid", None)
            if device_id:
                old_order = (
                    session.query(GoodsOrder)
                    .filter_by(
                        sdef_order_describe=device_id,
                        sdef_order_id=old_order_id,
                        sdef_order_is_delete=0,
                    )
                    .first()
                )
            else:
                old_order = (
                    session.query(GoodsOrder)
                    .filter_by(
                        sdef_order_device_id=open_id,
                        sdef_order_id=old_order_id,
                        sdef_order_is_delete=0,
                    )
                    .first()
                )
            if not old_order:
                session.close()
                return self.redirect("/404")

            if old_order.sdef_order_status != 1:
                session.close()
                return self.write("只有处于待支付的订单才能继续支付")

            # 继续支付时解除旧订单锁定的余额
            if old_order.sdef_order_balance_fee > Decimal("0"):
                redis = redis_util.client
                lock_balance_fee = redis.get("balance_lock_%s" % open_id)
                if lock_balance_fee:
                    lock_balance_fee = Decimal(lock_balance_fee.decode())
                    lock_balance_fee -= old_order.sdef_order_balance_fee
                    if lock_balance_fee > Decimal("0"):
                        redis.setex(
                            "balance_lock_%s" % open_id, 600, str(lock_balance_fee)
                        )
                    else:
                        redis.delete("balance_lock_%s" % open_id)
                    old_order.sdef_order_balance_fee = Decimal(0)
                    session.commit()

            cart_goods = json.loads(old_order.sdef_order_goods)

        # 再次购买
        elif t == "buy_again":
            old_order_id = self.get_argument("oid", None)
            old_order = (
                session.query(GoodsOrder)
                .filter_by(
                    sdef_order_device_id=open_id,
                    sdef_order_id=old_order_id,
                    sdef_order_is_delete=0,
                )
                .first()
            )
            if not old_order:
                session.close()
                return self.redirect("/404")

            if old_order.sdef_order_pay_status == 1 and old_order.sdef_order_type < 3:
                cart_goods = json.loads(old_order.sdef_order_goods)
            else:
                session.close()
                return self.write("只有已经付款的普通订单或者礼品订单才能再次购买")

        else:
            if device_id:
                invoke_push_topic(
                    device_id,
                    dict(
                        type=0,
                        message="已扫描，正在付款...",
                        data=None,
                    ),
                )
                cart_array = (
                    session.query(Carts).filter_by(sdef_cart_device_id=device_id).all()
                )
            else:
                cart_array = (
                    session.query(Carts).filter_by(sdef_cart_device_id=open_id).all()
                )

            if len(cart_array) > 0:
                cart_goods = json.loads(cart_array[0].sdef_cart_goods)

        for c in cart_goods:
            count = int(c["count"])
            goods_id = c["id"]
            # 必须是上架+未删除+库存大于0
            _goods = (
                session.query(Goods)
                .filter(Goods.sdef_goods_count > 0)
                .filter_by(
                    sdef_goods_id=goods_id, sdef_goods_status=1, sdef_goods_is_delete=0
                )
                .first()
            )
            if not _goods:
                session.close()
                return self.write(ret_msg(-1, error_message="商品库存不足或已下架"))

            if count > _goods.sdef_goods_count:
                session.close()
                return self.write(ret_msg(-1, error_message="商品库存不足"))

            goods_price = (
                _goods.sdef_goods_member_price
                if is_membership
                else _goods.sdef_goods_price
            )
            goods = dict(
                id=goods_id,
                count=count,
                balance_rate=_goods.sdef_goods_balance_rate,
                goods_img=json.loads(_goods.sdef_goods_thumbnail)[0],
                goods_name=_goods.sdef_goods_name,
                goods_price=goods_price,
            )
            balance_fee += (
                Decimal(_goods.sdef_goods_balance_rate) * Decimal(count) * goods_price
            )
            price_total += goods_price * Decimal(count)
            cart_goods_array.append(goods)

        if device_id:
            uid = device_id
        else:
            uid = open_id

        default_address = AddressHelper.get_default(uid)
        use_address = AddressHelper.get_use(uid)
        db = mongodb_util.db
        address = None
        if use_address:
            logger.debug("使用地址，address_id=%s" % use_address["address_id"])
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=use_address["address_id"])
                .first()
            )
        elif default_address:
            logger.debug("默认地址，address_id=%s" % default_address["address_id"])
            address = (
                session.query(UserAddress)
                .filter_by(sdef_address_id=default_address["address_id"])
                .first()
            )
        else:
            # 尝试获取第一个地址
            # address = session.query(UserAddress).filter_by(sdef_address_device_id=uid,
            #                                                sdef_address_is_del=0).order_by(
            #     UserAddress.sdef_address_id.desc()).first()

            result = db.sdec_address.find(
                {"user_id": open_id, "is_delete": False}
            ).sort("update_time", pymongo.DESCENDING)
            for a in result:
                address = (
                    session.query(UserAddress)
                    .filter_by(sdef_address_id=a["address_id"])
                    .first()
                )
                break

        # 获取账户余额
        enable_account_money = Decimal(0)
        account_money = (
            session.query(AccountMoney).filter_by(ebf_am_user_id=open_id).first()
        )
        if account_money:
            # 钱包余额需要减去redis缓存中暂扣的金额
            enable_account_money = account_money.ebf_am_money
            redis = redis_util.client
            lock_balance_fee = redis.get("balance_lock_%s" % open_id)
            if lock_balance_fee:
                enable_account_money = Decimal(enable_account_money) - Decimal(
                    lock_balance_fee.decode()
                )

            if account_money.ebf_am_is_forbid == 0 and enable_account_money > 0:
                if enable_account_money < balance_fee:
                    balance_fee = enable_account_money
            else:
                balance_fee = Decimal(0)
        else:
            balance_fee = Decimal(0)

        wechat_fee = price_total - balance_fee

        redis = redis_util.client

        # 页面唯一字符串，避免多次重复请求，重复支付
        unique_str = str(uuid.uuid1())
        redis.setex("unique_string_%s" % unique_str, 600, 1)
        context = dict(
            text="支付",
            cart_goods_array=cart_goods_array,
            price_total=price_total,
            wechat_fee=wechat_fee,
            balance_fee=balance_fee,
            device_id=device_id,
            address=address,
            account_money=account_money,
            enable_account_money=enable_account_money,
            unique_str=unique_str,
            order_type=type,
        )
        session.close()
        return self.render_html("mall/pay-confirm.html", **context)

    async def post(self):
        # 订单类型（1=普通订单，2=送礼订单，3=加盟费订单，4=特惠订单，5=餐券抵扣订单，6=礼品卡订单，7=新礼品订单，8=体验卡买单订单）
        order_type = int(self.get_argument("order_type", 1))
        # device_id!=None 为设备下的订单
        device_id = self.get_argument("d", None)
        t = self.get_argument("t", None)
        pay_type = int(self.get_argument("pay_type", PayType.WECHAT))
        balance_fee = Decimal(self.get_argument("balance_fee", 0))
        message = self.get_argument("message", "")
        cart_goods = self.get_argument("goods_list", None)
        if not cart_goods:
            # 参数兼容处理
            cart_goods = self.get_argument("cart_goods", None)
        serial_id = self.get_argument("serial_id", None)
        gift_key = self.get_argument("key", None)
        order_id = self.get_argument("order_id", None)

        order_describe = None
        enable_balance_fee = Decimal("0")
        open_id = await self.get_open_id()
        is_membership = self.is_membership(open_id)
        ip = self.request.remote_ip
        if pay_type not in [PayType.WECHAT, PayType.BALANCE]:
            return self.write("目前只支持微信支付和余额支付")

        redis = redis_util.client
        if order_type not in [
            OrderType.MEMBER,
            OrderType.GIFT_CARD,
            OrderType.FREE_CARD,
        ]:
            unique_str = self.get_argument("unique_str")
            unique_string = redis.get("unique_string_%s" % unique_str)
            if not unique_string:
                context = dict(
                    title="错误",
                    description="非法请求，请重新下单",
                )
                return self.render_html("error.html", **context)
            else:
                redis.delete("unique_string_%s" % unique_str)

        class UserAddress(object):
            pass

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        class Carts(object):
            pass

        class User(object):
            pass

        class AccountMoney(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        class GiftCard(object):
            pass

        class GiftInfo(object):
            pass

        class StoreGoods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_cart", "model": Carts},
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_address", "model": UserAddress},
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_account_money", "model": AccountMoney},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
                {"db_table": "ebt_gift_card", "model": GiftCard},
                {"db_table": "ebt_gift_info", "model": GiftInfo},
                {"db_table": "sdet_store_goods", "model": StoreGoods},
            ]
        )
        # 创建订单
        if device_id:
            user_id = device_id
        else:
            user_id = open_id

        # 加盟费订单:
        if order_type == OrderType.MEMBER:
            # type=0表示"线上分享", type=1表示"托管经营", type=2表示"线下开店", type="ad_funding"表示广告众筹
            # type=3表示"联合经营", type=4表示"委托经营", type = 5表示"新事业合伙人注册"
            type = self.get_argument("type", None)
            fee = Decimal(self.get_argument("fee", 0))
            num = int(self.get_argument("num", 1))
            unit = Decimal("1999")
            pay_fee = Decimal(unit * num)
            user = session.query(User).filter_by(ebf_user_id=open_id).first()
            if order_id:
                old_order = (
                    session.query(GoodsOrder).filter_by(sdef_order_id=order_id).first()
                )
                if not old_order:
                    session.close()
                    return self.write(ret_msg(code=-1, error_message="订单编号错误"))

                recommend_order_number = user.ebf_user_recommend_order_number
                real_fee = Decimal(
                    (config.TI_YAN_QUOTA - recommend_order_number) * 9.9
                ).quantize(Decimal("0.00"))
                if fee < real_fee:
                    session.close()
                    return self.write(ret_msg(code=-1, error_message="支付金额错误"))
                old_order_status = old_order.sdef_order_status
                if (
                    old_order.sdef_order_type != OrderType.TIYAN
                    or old_order_status != OrderStatus.WAIT_VALID
                ):
                    session.close()
                    return self.write(ret_msg(code=-1, error_message="非待激活的体验订单"))
            else:
                if type == "ad_funding":
                    pay_fee = Decimal(286 * num)
                    if pay_fee != fee:
                        return self.write(ret_msg(code=-1, error_message="支付金额与数目不匹配"))
                else:
                    type = int(type)
                    if type == 0:
                        if fee != Decimal("980"):
                            logger.info("fee=%s" % fee)
                            return self.write(ret_msg(code=-1, error_message="支付金额错误"))
                    elif type == 5:
                        if fee != Decimal("20000"):
                            logger.error("fee=%s" % fee)
                            return self.write(ret_msg(code=-1, error_message="支付金额错误"))
                    else:
                        logger.info("fee=%s, pay_fee=%s" % (fee, pay_fee))
                        if fee != pay_fee:
                            return self.write(
                                ret_msg(code=-1, error_message="支付金额与数目不匹配")
                            )

            now = datetime.datetime.now()
            order = GoodsOrder()
            out_trade_no = generator_trade_no()
            order.sdef_order_id = out_trade_no
            order.sdef_order_factory_uid = FACTORY_UID
            order.sdef_order_device_id = open_id
            order.sdef_order_fee = fee
            order.sdef_order_name = "思达尔加盟费"
            order.sdef_order_type = OrderType.MEMBER
            order.sdef_order_pay_type = pay_type
            order.sdef_order_ip = ip
            order.sdef_order_delivery_fee = 0  # 邮费
            order.sdef_order_create_time = now
            if order_id:
                order.sdef_order_remarks = f"体验订单激活:{order_id}"
            elif type == 0:
                order_describe = "online"
                order.sdef_order_describe = order_describe  # 线上分享
                order.sdef_order_message = "1"  # 不需要每日返还收益标志
            elif type == 1:
                order_describe = "crowdfunding"
                order.sdef_order_describe = order_describe  # 托管经营
            elif type == 2:
                order_describe = "underline"
                order.sdef_order_describe = order_describe  # 线下开店
                order.sdef_order_message = "1"  # 不需要每日返还收益标志
            elif type == 3:
                order_describe = "partnershop"
                order.sdef_order_describe = order_describe  # 联合经营
                order.sdef_order_message = "1"
            elif type == 4:
                order_describe = "delegate"
                order.sdef_order_describe = order_describe  # 委托经营
                order.sdef_order_message = "1"
            elif type == 5:
                order_describe = "新事业合伙人注册"
                order.sdef_order_describe = order_describe
                order.sdef_order_message = "1"
            elif type == "ad_funding":
                order_describe = "adfunding"
                order.sdef_order_describe = order_describe
                order.sdef_order_message = "1"
            else:
                session.close()
                return self.write(ret_msg(code=-1, error_message="不支持的分享类型！"))

            if pay_type == PayType.WECHAT:
                order.sdef_order_status = OrderStatus.WAIT_PAY
                order.sdef_order_pay_status = PayStatus.NOT_PAY
            else:
                return self.write(ret_msg(code=-1, error_message="请使用微信支付！"))

            if type == "ad_funding" and num < 10:
                agency_uid = DEFAULT_AGENCY_UID
                if user.ebf_user_agency_uid:
                    agency_uid = user.ebf_user_agency_uid
            else:
                if order_id:
                    agency_uid = (
                        user.ebf_user_agency_uid
                        if user.ebf_user_agency_uid
                        else DEFAULT_AGENCY_UID
                    )
                else:
                    user_agency = (
                        session.query(UserAgency)
                        .filter_by(ebf_ua_bind_user_id=open_id)
                        .first()
                    )
                    if not user_agency:
                        return self.write(ret_msg(code=-1, error_message="请先注册成为酒庄代表！"))
                    agency = (
                        session.query(Agency)
                        .filter_by(ebf_agency_id=user_agency.ebf_agency_id)
                        .first()
                    )
                    agency_uid = agency.ebf_agency_uid
                    if user and user.ebf_user_agency_uid != agency_uid:
                        user.ebf_user_agency_uid = agency_uid

            order.sdef_order_agency_uid = agency_uid
            session.add(order)
            if type != "ad_funding" and not order_id:
                inviter_oid = self.get_argument("inviter_oid", None)
                logger.info(
                    "inviter_oid=%s, oid=%s, order_id=%s"
                    % (inviter_oid, open_id, out_trade_no)
                )
                recommend_user = user.ebf_user_recommend_user
                if (
                    inviter_oid
                    and recommend_user != inviter_oid
                    and inviter_oid != open_id
                ):
                    user.ebf_user_recommend_user = inviter_oid
                    msg = (
                        "更新推荐人: recommend_user={}, inviter_oid={}, oid={}, order_id={}"
                    )
                    logger.info(
                        msg.format(recommend_user, inviter_oid, open_id, out_trade_no)
                    )
        # 非加盟费订单:
        else:
            default_address = AddressHelper.get_default(user_id)
            use_address = AddressHelper.get_use(user_id)
            db = mongodb_util.db
            address = None
            if use_address:
                logger.debug("使用地址，address_id=%s" % use_address["address_id"])
                address = (
                    session.query(UserAddress)
                    .filter_by(sdef_address_id=use_address["address_id"])
                    .first()
                )
            elif default_address:
                logger.debug("默认地址，address_id=%s" % default_address["address_id"])
                address = (
                    session.query(UserAddress)
                    .filter_by(sdef_address_id=default_address["address_id"])
                    .first()
                )
            else:
                result = db.sdec_address.find(
                    {"user_id": open_id, "is_delete": False}
                ).sort("update_time", pymongo.DESCENDING)

                for a in result:
                    address = (
                        session.query(UserAddress)
                        .filter_by(sdef_address_id=a["address_id"])
                        .first()
                    )
                    break

            # 订单商品判断
            if not cart_goods:
                session.close()
                return self.write("订单商品列表为空")
            if not isinstance(cart_goods, list):
                cart_goods = json.loads(cart_goods)

            cart_goods_array = []
            price_total = Decimal("0")
            # 送礼订单允许地址为空
            if not address and order_type not in [
                OrderType.GIFT,
                OrderType.GIFT_CARD,
                OrderType.FREE_CARD,
            ]:
                session.close()
                return self.write("请先完善收货地址")

            user = session.query(User).filter_by(ebf_user_id=open_id).first()

            if order_type == OrderType.FREE_CARD:
                #  餐厅消费免费喝酒体验卡订单
                store_id = self.get_argument("store_id", None)
                fee = self.get_argument("fee", None)
                level = user.ebf_user_level
                lock_balance_fee = Decimal("0")
                free_filters = dict(
                    sdef_order_device_id=open_id,
                    sdef_order_type=OrderType.FREE_CARD,
                    sdef_order_pay_status=PayStatus.SUCCESS,
                )
                free_order = (
                    session.query(GoodsOrder)
                    .filter_by(**free_filters)
                    .order_by(GoodsOrder.sdef_order_id.desc())
                    .first()
                )
                if free_order:
                    free_pay_time = free_order.sdef_order_pay_time
                    minus_time = (
                        datetime.datetime.now() - free_pay_time
                    ).total_seconds() / 60
                    if minus_time <= float(120):
                        session.close()
                        return self.write("两个小时内只能使用一次酒卡")
                if not level:
                    session.close()
                    return self.write(f"用户没有免费喝酒资格: {level}")
                if not fee:
                    session.close()
                    return self.write("缺少参数消费金额")
                if not store_id:
                    session.close()
                    return self.write("缺少参数门店编号")
                fee = Decimal(fee)
                agency = session.query(Agency).filter_by(ebf_agency_id=store_id).first()
                if not agency:
                    session.close()
                    return self.write("门店编号错误")
                if fee < Decimal(100):
                    session.close()
                    return self.write("实付金额不能低于100元")
                store_name = agency.ebf_agency_name
                store_uid = agency.ebf_agency_uid
                cart_goods = [
                    {"id": "565766647414853", "count": 1},
                    {"id": "523948088470142", "count": 1},
                ]

                for c in cart_goods:
                    count = int(c["count"])
                    goods_id = c["id"]
                    if order_type == OrderType.GIFT_CARD:
                        _goods = (
                            session.query(Goods)
                            .filter_by(sdef_goods_id=goods_id)
                            .first()
                        )
                        goods_price = (
                            _goods.sdef_goods_member_price
                            if is_membership
                            else _goods.sdef_goods_price
                        )
                        goods_member_price = _goods.sdef_goods_member_price
                    else:
                        _goods = (
                            session.query(StoreGoods)
                            .filter_by(
                                sdef_goods_id=goods_id,
                                sdef_goods_store_id=store_id,
                                sdef_goods_factory_uid=config.FACTORY_UID,
                            )
                            .first()
                        )
                        if not _goods:
                            session.close()
                            return self.write(f"商品不存在: {goods_id}")
                        if (
                            _goods.sdef_goods_count < count
                            and goods_id == "523948088470142"
                        ):
                            session.close()
                            return self.write(f"商品库存不足: {goods_id}")
                        goods_price = fee if goods_id == "565766647414853" else 0
                        goods_member_price = fee if goods_id == "565766647414853" else 0
                    goods_img = json.loads(_goods.sdef_goods_thumbnail)[0]
                    # 下单时减少库存
                    if _goods.sdef_goods_count >= count:
                        _goods.sdef_goods_count -= count
                    goods = dict(
                        id=goods_id,
                        count=count,
                        goods_img=goods_img,
                        goods_name=_goods.sdef_goods_name,
                        goods_price=goods_price,
                        goods_member_price=goods_member_price,
                        goods_pin_price=_goods.sdef_goods_pin_price,
                        balance_rate=_goods.sdef_goods_balance_rate,
                        rate=_goods.sdef_goods_rate,
                        master_rate=_goods.sdef_goods_master_rate,
                        invite_rate=_goods.sdef_goods_invite_rate,
                        invite_invite_rate=_goods.sdef_goods_invite_invite_rate,
                        career_rate=_goods.sdef_goods_career_rate,
                        invite_career_rate=_goods.sdef_goods_invite_career_rate,
                        supplier=_goods.sdef_goods_supplier,
                        goods_cost=_goods.sdef_goods_cost,
                    )
                    enable_balance_fee += (
                        Decimal(_goods.sdef_goods_balance_rate)
                        * Decimal(count)
                        * goods_price
                    )
                    price_total += goods_price * Decimal(count)
                    cart_goods_array.append(goods)
                order_name = "体验卡买单订单"
                wechat_fee = fee
                agency_uid = store_uid
            else:
                # 非餐厅消费免费喝酒体验卡订单（普通订单和其他订单）
                if order_type == OrderType.GIFT_CARD:
                    # 送礼订单特别处理
                    gift_card = False
                    if not cart_goods:
                        gift_card = True
                        cart_goods = [{"id": "562899833710732", "count": 1}]  # 原礼品卡礼品
                    recommend_user = user.ebf_user_recommend_user
                    logger.info(
                        f"serial_id={serial_id}, recommend_user={recommend_user}"
                    )

                    if gift_card:
                        # 原礼品卡订单处理
                        logger.info(f"原礼品卡订单 礼品卡编号{serial_id}")
                        qr = session.query(GiftCard).filter_by(id=serial_id).first()
                    else:
                        # 新送礼订单处理
                        logger.info(f"新送礼订单 礼品编号{serial_id}")
                        qr = session.query(GiftInfo).filter_by(id=serial_id).first()
                    if not qr:
                        session.close()
                        return self.write("礼品卡号错误")
                    qr_status = qr.status
                    if qr_status == 1:
                        return self.redirect(
                            f"/static/giftcard/index.html#/getGift?id={serial_id}&code={gift_key}"
                        )
                    elif qr_status == 2:
                        return self.redirect(
                            f"/static/giftcard/index.html#/nonvalid?id={serial_id}&code={gift_key}"
                        )

                for c in cart_goods:
                    _goods = (
                        session.query(Goods)
                        .filter_by(
                            sdef_goods_id=c["id"],
                            sdef_goods_status=1,
                            sdef_goods_is_delete=0,
                        )
                        .first()
                    )

                    if not _goods:
                        session.close()
                        return self.write(f"编号为{c['id']}的商品已下架")

                    count = int(c["count"])
                    goods_id = str(c["id"])
                    goods_img = json.loads(_goods.sdef_goods_thumbnail)[0]
                    goods_price = (
                        _goods.sdef_goods_member_price
                        if is_membership
                        else _goods.sdef_goods_price
                    )

                    # 检查商品是否限购
                    if _goods.sdef_goods_limit_num != 0:
                        if _goods.sdef_goods_limit_num <= count:
                            continue

                    # 下单时减少库存
                    if _goods.sdef_goods_count >= count:
                        _goods.sdef_goods_count -= count
                    else:
                        continue

                    goods = dict(
                        id=goods_id,
                        count=count,
                        goods_img=goods_img,
                        goods_name=_goods.sdef_goods_name,
                        goods_price=goods_price,
                        goods_member_price=_goods.sdef_goods_member_price,
                        goods_pin_price=_goods.sdef_goods_pin_price,
                        balance_rate=_goods.sdef_goods_balance_rate,
                        rate=_goods.sdef_goods_rate,
                        master_rate=_goods.sdef_goods_master_rate,
                        invite_rate=_goods.sdef_goods_invite_rate,
                        invite_invite_rate=_goods.sdef_goods_invite_invite_rate,
                        career_rate=_goods.sdef_goods_career_rate,
                        invite_career_rate=_goods.sdef_goods_invite_career_rate,
                        supplier=_goods.sdef_goods_supplier,
                        goods_cost=_goods.sdef_goods_cost,
                    )
                    enable_balance_fee += (
                        Decimal(_goods.sdef_goods_balance_rate)
                        * Decimal(count)
                        * goods_price
                    )
                    price_total += goods_price * Decimal(count)
                    cart_goods_array.append(goods)

                # 获取账户余额
                account_money = (
                    session.query(AccountMoney)
                    .filter_by(ebf_am_user_id=open_id)
                    .first()
                )
                lock_balance_fee = redis.get("balance_lock_%s" % open_id)
                if account_money:
                    # 钱包余额需要减去redis缓存中暂扣的金额
                    enable_account_money = account_money.ebf_am_money
                    if lock_balance_fee:
                        enable_account_money = Decimal(enable_account_money) - Decimal(
                            lock_balance_fee.decode()
                        )
                    if (
                        account_money
                        and account_money.ebf_am_is_forbid == 0
                        and enable_account_money > 0
                    ):
                        if enable_account_money < enable_balance_fee:
                            enable_balance_fee = enable_account_money
                    else:
                        enable_balance_fee = Decimal("0")
                else:
                    enable_balance_fee = Decimal("0")

                if enable_balance_fee < balance_fee:
                    session.close()
                    return self.write("可抵扣余额错误")

                wechat_fee = price_total - balance_fee
                agency_uid = user.ebf_user_agency_uid

                if order_type == OrderType.GIFT_CARD:
                    order_name = "送礼订单"
                else:
                    order_name = "思达尔商城订单"
                logger.info(
                    "price_total=%s,balance_fee=%s,wechat_fee=%s"
                    % (price_total, balance_fee, wechat_fee)
                )

                if wechat_fee < Decimal("0.01"):
                    pay_type = PayType.BALANCE  # 支付方式直接标记为余额支付
                    if balance_fee < Decimal("0.01"):
                        pay_type = PayType.COUPON  # 支付方式直接标记为优惠券支付

            now = datetime.datetime.now()
            goods_order = GoodsOrder()
            out_trade_no = generator_trade_no()
            goods_order.sdef_order_id = out_trade_no
            goods_order.sdef_order_factory_uid = FACTORY_UID
            goods_order.sdef_order_device_id = open_id  # 微信用户openId
            goods_order.sdef_order_fee = wechat_fee
            goods_order.sdef_order_goods = json.dumps(cart_goods_array, cls=JSONEncoder)
            goods_order.sdef_order_balance_fee = balance_fee
            goods_order.sdef_order_name = order_name
            goods_order.sdef_order_message = message

            if device_id:
                goods_order.sdef_order_describe = device_id
            else:
                goods_order.sdef_order_describe = "微信商城订单"

            if pay_type == PayType.WECHAT:
                goods_order.sdef_order_status = OrderStatus.WAIT_PAY
                goods_order.sdef_order_pay_status = PayStatus.NOT_PAY
            else:
                goods_order.sdef_order_status = OrderStatus.WAIT_EXPRESS
                goods_order.sdef_order_pay_status = PayStatus.SUCCESS
                goods_order.sdef_order_pay_time = now

            # 送礼的订单不需要地址
            goods_order.sdef_order_pay_type = pay_type
            if order_type in [OrderType.GIFT, OrderType.GIFT_CARD]:
                goods_order.sdef_order_type = order_type
                goods_order.sdef_order_courier_phone = serial_id
                goods_order.sdef_order_courier_name = gift_key
            elif order_type == OrderType.FREE_CARD:
                goods_order.sdef_order_type = order_type
                goods_order.sdef_order_store_id = int(store_id)
                goods_order.sdef_order_ship_type = 1
            else:
                if order_type == OrderType.BARGAIN_PRICE:
                    goods_order.sdef_order_type = order_type
                else:
                    goods_order.sdef_order_type = OrderType.NORMAL
                goods_order.sdef_order_address_id = address.sdef_address_id

            goods_order.sdef_order_ip = ip
            goods_order.sdef_order_delivery_fee = 0  # 邮费
            goods_order.sdef_order_create_time = now
            goods_order.sdef_order_agency_uid = agency_uid
            session.add(goods_order)
            redis.setex("order_id_%s" % out_trade_no, 86400, out_trade_no)

            if t == "buy":
                pass
            elif t == "retry":
                old_order_id = self.get_argument("oid", None)
                if device_id:
                    old_order = (
                        session.query(GoodsOrder)
                        .filter_by(
                            sdef_order_describe=device_id,
                            sdef_order_id=old_order_id,
                            sdef_order_is_delete=0,
                        )
                        .all()[0]
                    )
                else:
                    old_order = (
                        session.query(GoodsOrder)
                        .filter_by(
                            sdef_order_device_id=open_id,
                            sdef_order_id=old_order_id,
                            sdef_order_is_delete=0,
                        )
                        .all()[0]
                    )

                if old_order.sdef_order_status != OrderStatus.WAIT_PAY:
                    session.close()
                    return self.write("只有处于待支付的订单才能继续支付")
                # 获取之前的支付信息，创建完新订单之后将之前的订单标记为删除
                old_order.sdef_order_is_delete = 1
                old_order.sdef_order_delete_time = datetime.datetime.now()
                logger.debug("将旧订单标记为删除：%s" % old_order_id)
            elif t == "buy_again":
                pass
            else:
                # 并清空购物车
                if device_id:
                    ret = (
                        session.query(Carts)
                        .filter_by(sdef_cart_device_id=device_id)
                        .delete()
                    )
                else:
                    ret = (
                        session.query(Carts)
                        .filter_by(sdef_cart_device_id=open_id)
                        .delete()
                    )
                logger.info("delete cart ret=%s" % ret)

            if pay_type == PayType.BALANCE:
                logger.info("余额支付")
                account_money = (
                    session.query(AccountMoney)
                    .filter_by(ebf_am_user_id=open_id)
                    .first()
                )
                if not account_money:
                    # 没有账户时创建账户
                    am = AccountMoney()
                    am.ebf_am_user_id = user_id
                    am.ebf_am_account_type = 2
                    am.ebf_am_money = 0
                    am.ebf_am_cash = 0
                    am.ebf_am_is_forbid = 0
                    am.ebf_am_create_date = datetime.datetime.utcnow()
                    am.ebf_am_remarks = remarks
                    session.add(am)
                    session.commit()
                    session.close()
                    return self.write("账户未开通")

                if account_money.ebf_am_is_forbid != 0:
                    session.close()
                    return self.write("账户不可用")

                if account_money.ebf_am_money < price_total:
                    session.close()
                    return self.write("账户余额不足")
                # 计算提成金额
                # 余额的不分成时 可以通过后台将余额的分成比例设为0来解决
                price_total_rate = calculate_order_fee(goods_order.sdef_order_goods)[0]
                # 扣款并添加扣款记录，同时往ebt_pay表中添加一条订单
                if not BalanceHandler.reduce_money(
                    open_id, out_trade_no, price_total, price_total_rate, ip
                ):
                    session.close()
                    return self.write("扣款失败")

                is_success = create_balance_record(open_id, price_total, out_trade_no)
                if is_success:
                    logger.info(
                        "创建余额消费记录成功:user_id=%s,out_trade_no=%s"
                        % (open_id, out_trade_no)
                    )
                else:
                    logger.error(
                        "创建余额消费记录失败:user_id=%s,out_trade_no=%s"
                        % (open_id, out_trade_no)
                    )

                context = dict(
                    trade_no=out_trade_no,
                )

                if order_type == OrderType.GIFT_CARD:
                    if int(serial_id) > 1000000000:  # 礼品卡订单处理
                        gf_card = (
                            session.query(GiftCard).filter_by(id=serial_id).first()
                        )
                        ua = (
                            session.query(UserAgency)
                            .filter_by(ebf_ua_bind_user_id=user_id)
                            .first()
                        )
                        agency = (
                            session.query(Agency)
                            .filter_by(ebf_agency_id=ua.ebf_agency_id)
                            .first()
                        )
                        agency_type = agency.ebf_agency_type
                        sub_type = agency.ebf_agency_sub_type
                        if agency_type == AgencyType.NORMAL:
                            agency.ebf_agency_type = AgencyType.PROFESSIONAL
                        if sub_type < 2:
                            agency.ebf_agency_sub_type = 2
                        gf_card.gift_card_order_id = out_trade_no
                        gf_card.status = 1
                        gf_card.update_time = datetime.datetime.now()
                    else:  # 送礼订单处理
                        gf_card = (
                            session.query(GiftInfo).filter_by(id=serial_id).first()
                        )
                        gf_card.gift_sender_order_id = out_trade_no
                        gf_card.status = 1
                        gf_card.update_time = datetime.datetime.now()

                session.commit()
                # 生成预收益订单
                tasks.order_paid.delay(out_trade_no)
                # 支付成功后通知屏端
                if device_id:
                    invoke_push_topic(
                        device_id,
                        dict(
                            type=1,
                            message='支付成功<i class="weui-icon-success"></i>',
                            data="/pad/order?device_id=%s" % device_id,
                        ),
                    )
                session.close()

                if order_type == OrderType.GIFT_CARD:
                    # 送礼订单余额支付成功后跳转
                    return self.redirect(
                        f"/static/app1/index.html#/sendFriends?order_id={out_trade_no}&key={gift_key}"
                    )
                return self.render_html("mall/balance_pay.html", **context)

        try:
            session.commit()
        except Exception as e:
            logger.exception(e)
            session.rollback()
            session.close()
            return self.finish("订单创建异常")

        app_id = MP_APP_ID
        time_stamp = int(str(time.time()).split(".")[0])
        nonce_str = WechatPay.generate_nonce_str()
        # 生成预支付交易单
        logger.info("生成预支付交易单")

        if order_type == OrderType.MEMBER:
            try:
                prepay_id = WechatPay.order(
                    out_trade_no, int(fee * 100), "加盟费订单", ip, nonce_str, open_id
                )
            except Exception as e:
                logger.exception(e)
                session.close()
                return self.finish(ret_msg(code=-1, error_message="支付异常"))
        else:
            try:
                prepay_id = WechatPay.order(
                    out_trade_no, int(wechat_fee * 100), "商城订单", ip, nonce_str, open_id
                )

                # 将暂扣的余额存入redis中，超时时间10分钟，微信支付回调时直接扣余额即可
                if lock_balance_fee:
                    lock_balance_fee = Decimal(lock_balance_fee.decode()) + balance_fee
                else:
                    lock_balance_fee = balance_fee

                redis.setex("balance_lock_%s" % open_id, 600, str(lock_balance_fee))
                if use_address and order_type not in [
                    OrderType.GIFT_CARD,
                    OrderType.FREE_CARD,
                ]:
                    if default_address:
                        if use_address["address_id"] != default_address["address_id"]:
                            is_default = True
                            is_use = True
                            AddressHelper.set_default(
                                open_id,
                                default_address["address_id"],
                                is_default,
                                is_use,
                            )
                    else:
                        is_default = False
                        is_use = False
                        AddressHelper.set_default(
                            open_id, use_address["address_id"], is_default, is_use
                        )
            except Exception as e:
                logger.exception(e)
                session.close()
                return self.write("支付异常")

        package = "prepay_id=" + prepay_id
        # 计算jsapi签名
        logger.info("计算jsapi签名" + package)
        sign_value = WechatPay.get_jsapi_pay_sign(time_stamp, nonce_str, package, "MD5")
        host = self.request.host
        url_params = self.request.query
        request_path = self.request.path
        protocol = self.request.protocol
        full_url = protocol + "://" + host + request_path
        if url_params:
            full_url += "?" + url_params

        jsapi_ticket = self.get_jsapi_ticket()
        signature = Wechat_Base.signature(nonce_str, time_stamp, full_url, jsapi_ticket)
        logging.debug("signature：%s, url:%s" % (signature, full_url))

        # 微信支付的加入消息队列，6分钟后检查是否已支付
        add_mq_task(out_trade_no, message_type=1, delay=360)
        # 如果是礼品订单，则在设定时间后检查是否需要退款
        if order_type in [OrderType.GIFT, OrderType.GIFT_CARD]:
            logger.info(f"准备添加送礼订单自动退款延时任务 order_id={out_trade_no}")
            if not add_mq_task(
                out_trade_no, message_type=2, delay=GIFT_ORDER_REFUND_TIMEOUT
            ):
                logger.error(f"添加送礼订单自动退款延时任务失败！order_id={out_trade_no}")

        context = dict(
            text="支付中",
            trade_no=out_trade_no,
            app_id=app_id,
            time_stamp=time_stamp,
            nonce_str=nonce_str,
            sign_value=sign_value,
            prepay_id=prepay_id,
            signature=signature,
            full_url=full_url,
            order_type=order_type,
            describe=order_describe,
            serial_id=serial_id,
            gift_key=gift_key,
            store_name=store_name if order_type == OrderType.FREE_CARD else None,
            fee="%.2f" % fee if order_type == OrderType.FREE_CARD else None,
            store_id=store_id if order_type == OrderType.FREE_CARD else None,
            order_id=out_trade_no,
        )
        session.close()
        return self.render_html("mall/wechat_pay.html", **context)


class WechatNotify(BaseHandler):
    async def get(self):
        open_id = await self.get_open_id()
        context = dict(text=open_id)
        return self.render("developing.html", **context)

    async def post(self):
        # 微信支付回调
        logger.info("wechat_async_notify")

        pay_info = self.request.body.decode("utf8").replace("\n", "").replace(" ", "")
        if not pay_info:
            return self.write(wechat_resp(40001))

        logger.info(pay_info)
        params = xmltodict.parse(pay_info, encoding="utf-8").get("xml", None)
        logger.info("xml解析成功")
        # 参数传入错误
        if not params:
            ret = wechat_resp(40001)
            logger.info(ret)
            return self.write(ret)

        # 验证传输码
        return_code = params.get("return_code", None)
        if not return_code or return_code != "SUCCESS":
            ret = wechat_resp(46011)
            logger.info(ret)
            return self.write(ret)

        # 验证交易码
        result_code = params.get("result_code", None)
        if not result_code or result_code != "SUCCESS":
            ret = wechat_resp(46012)
            logger.info(ret)
            return self.write(ret)

        # 验证微信消息
        if not weixin_verify(params):
            ret = wechat_resp(46005)
            logger.info(ret)
            return self.write(ret)

        # 验证订单号
        out_trade_no = params.get("out_trade_no", None)
        if not out_trade_no:
            ret = wechat_resp(46004)
            logger.info(ret)
            return self.write(ret)

        # 验证订单信息
        # third_trade_no = params.get('transaction_id', '')

        class GoodsOrder(object):
            pass

        class User(object):
            pass

        class Pay(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        class Benefit(object):
            pass

        class CouponUser(object):
            pass

        class CouponOrder(object):
            pass

        class GiftCard(object):
            pass

        class GiftInfo(object):
            pass

        class UserInventory(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_pay", "model": Pay},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
                {"db_table": "sdet_benefit", "model": Benefit},
                {"db_table": "ebt_coupon_user", "model": CouponUser},
                {"db_table": "ebt_coupon_order", "model": CouponOrder},
                {"db_table": "ebt_gift_card", "model": GiftCard},
                {"db_table": "ebt_gift_info", "model": GiftInfo},
                {"db_table": "ebt_user_inventory", "model": UserInventory},
            ]
        )
        _order_array = (
            session.query(GoodsOrder).filter_by(sdef_order_id=out_trade_no).all()
        )
        if len(_order_array) == 0:
            # 订单不存在异常（订单不存在的时候，厂商和合伙人都为空）
            ret = wechat_resp(46002)
            logger.info(ret)
            session.close()
            return self.write(ret)
        if len(_order_array) > 1:
            # 订单多条记录异常
            ret = wechat_resp(46003)
            logger.info(ret)
            session.close()
            return self.write(ret)

        pay = _order_array[0]

        # 如果订单记录的支付状态不是0（未完成）， 则直接返回即可，不需要继续处理
        if pay.sdef_order_pay_status != PayStatus.NOT_PAY:
            session.close()
            return self.write(wechat_resp(0))

        # 验证支付费用是否一致
        pay_fee = pay.sdef_order_fee
        total_fee = params.get("total_fee", None)
        logging.debug("pay_fee:%s,total_fee:%s" % (pay_fee, total_fee))
        if (
            (not pay_fee)
            or (not total_fee)
            or (("%.2f" % (float(pay_fee) * 100)) != ("%.2f" % float(total_fee)))
        ):
            ret = wechat_resp(46001)
            logger.info(ret)
            session.close()
            return self.write(ret)

        # 微信回调中拿不到支付者的账号信息，直接使用openid代替
        # buyer_email = params.get('openid', None)
        # 更新订单为已支付
        logger.info("out_trade_no=%s" % out_trade_no)
        # 订单状态（0 = 未知，1 = 待支付，2 = 待发货，3 = 已发货，4 = 完成, 5 = 失效）

        open_id = params.get("openid", None)
        redis = redis_util.client
        flag = redis.get("wechat_notify_%s" % out_trade_no)

        # 加盟费支付后处理
        if pay.sdef_order_type == OrderType.MEMBER:
            pay.sdef_order_status = OrderStatus.COMPLETE
            pay.sdef_order_pay_status = PayStatus.SUCCESS
            pay.sdef_order_pay_time = datetime.datetime.now()

            session.commit()
            session.close()
            # 异步触发加盟费订单已支付消息
            if not flag:
                redis.setex("wechat_notify_%s" % out_trade_no, 3600, 1)
                tasks.membership_order_paid.delay(out_trade_no)
            return self.write(wechat_resp(0))

        if pay.sdef_order_type in [OrderType.FREE_CARD]:
            pay.sdef_order_status = OrderStatus.COMPLETE
        elif pay.sdef_order_type == OrderType.TIYAN:
            pay.sdef_order_status = OrderStatus.WAIT_VALID
            if not add_mq_task(out_trade_no, message_type=7, delay=3 * 24 * 3600):
                logger.info(f"3天后体验订单自动过期加入任务队列失败：out_trade_no={out_trade_no}")
        else:
            pay.sdef_order_status = OrderStatus.WAIT_EXPRESS
        # 支付状态（0 = 未支付，1 = 支付成功，2 = 退款）
        pay.sdef_order_pay_status = PayStatus.SUCCESS
        pay.sdef_order_pay_time = datetime.datetime.now()
        if pay.sdef_order_coupon_fee > 0:
            co = session.query(CouponOrder).filter_by(order_id=out_trade_no).first()
            cu_id = co.coupon_user_id
            cu = session.query(CouponUser).filter_by(id=cu_id).one()
            co.status = 1
            cu.status = 1
        # session.flush()
        user_id = pay.sdef_order_device_id
        if not flag:
            redis.setex("wechat_notify_%s" % out_trade_no, 3600, 1)
            # 扣除锁定的余额
            if pay.sdef_order_balance_fee > Decimal("0"):
                is_success = update_account_money(user_id, -pay.sdef_order_balance_fee)
                # todo 去掉redis中保存的锁定余额？
                # todo 取消订单时解锁余额
                if not is_success:
                    logger.error(
                        "扣款异常:user_id=%s,out_trade_no=%s" % (user_id, out_trade_no)
                    )
                else:
                    result = create_balance_record(
                        user_id, pay.sdef_order_balance_fee, out_trade_no
                    )
                    if result:
                        logger.info(
                            "创建余额消费记录成功:user_id=%s,out_trade_no=%s"
                            % (user_id, out_trade_no)
                        )
                    else:
                        logger.error(
                            "创建余额消费记录失败:user_id=%s,out_trade_no=%s"
                            % (user_id, out_trade_no)
                        )

            if pay.sdef_order_type == OrderType.GIFT_CARD:
                serial_id = int(pay.sdef_order_courier_phone)
                if serial_id > 1000000000:  # 礼品卡订单处理
                    gf_card = session.query(GiftCard).filter_by(id=serial_id).first()
                    ua = (
                        session.query(UserAgency)
                        .filter_by(ebf_ua_bind_user_id=user_id)
                        .first()
                    )
                    agency = (
                        session.query(Agency)
                        .filter_by(ebf_agency_id=ua.ebf_agency_id)
                        .first()
                    )
                    agency_type = agency.ebf_agency_type
                    sub_type = agency.ebf_agency_sub_type
                    if agency_type == AgencyType.NORMAL:
                        agency.ebf_agency_type = AgencyType.PROFESSIONAL
                    if sub_type < 2:
                        agency.ebf_agency_sub_type = 2
                    gf_card.gift_card_order_id = out_trade_no
                    gf_card.status = 1
                    gf_card.update_time = datetime.datetime.now()
                else:
                    # 电子礼品卡-送礼订单
                    gf_card = session.query(GiftInfo).filter_by(id=serial_id).first()
                    gf_card.gift_sender_order_id = out_trade_no
                    gf_card.status = 1
                    gf_card.update_time = datetime.datetime.now()
                    # 定时自动退款
                    logger.info(f"wechat_notify: 准备添加送礼订单自动退款任务 order_id={out_trade_no}")
                    if not add_mq_task(
                        out_trade_no, message_type=2, delay=GIFT_ORDER_REFUND_TIMEOUT
                    ):
                        logger.error(f"wechat_notify: 添加送礼订单自动退款失败！order_id={out_trade_no}")

            # 减少用户拼购库存
            if pay.sdef_order_type == OrderType.PINQU:
                goods_packing_id = ["571983673114813", "571983568187916"]  # 商品包装ID列表
                cart_goods = json.loads(pay.sdef_order_goods)
                goods_info = list(
                    filter(lambda g: g["id"] not in goods_packing_id, cart_goods)
                )[0]
                goods_id = goods_info["id"]
                count = goods_info["count"]
                filters = dict(user_id=user_id, goods_id=goods_id, status=1)
                ui = session.query(UserInventory).filter_by(**filters).first()
                pinqu_id = redis.get(f"pinqu_{out_trade_no}")
                access_record = ui.access_record
                logger.info(f"access_record={access_record}")
                is_minus = out_trade_no in access_record
                if not is_minus and not pinqu_id:
                    log_msg = f"minus_inventory: order_id={out_trade_no} old_inventory={ui.inventory} count=-{count}"
                    logger.info(log_msg)
                    redis.setex(f"pinqu_{out_trade_no}", 3600, 1)
                    access_record = json.loads(access_record)
                    access_record["minus"].append({out_trade_no: count})
                    ui.access_record = json.dumps(access_record)
                    ui.update_time = datetime.datetime.now()
                    ui.inventory -= count

            if pay.sdef_order_store_id:
                # 门店订单店内消费/自提/外卖订单8小时之后自动确认收货
                if pay.sdef_order_ship_type in [1, 2, 3]:
                    if not add_mq_task(out_trade_no, message_type=6, delay=8 * 3600):
                        logger.info(f"8小时后自动确认收货加入任务队列失败：out_trade_no={out_trade_no}")

            # 提交
            session.commit()
            # 异步触发订单已支付消息
            tasks.order_paid.delay(out_trade_no)
            logger.info(f"支付回调处理成功: order_id={out_trade_no}")
            if pay.sdef_order_describe != "微信商城订单":
                # 通知屏端
                invoke_push_topic(
                    pay.sdef_order_describe,
                    dict(
                        type=1,
                        message='支付成功<i class="weui-icon-success"></i>',
                        data="/pad/order?device_id=%s" % pay.sdef_order_describe,
                    ),
                )
        session.close()
        return self.write(wechat_resp(0))


class Received(BaseHandler):
    async def get(self, order_id):
        """
        订单确认收货
        """
        logger.info("调用确认收货接口：order_id=%s,ip=%s" % (order_id, self.request.remote_ip))

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        _filter = dict(
            sdef_order_id=order_id,
        )
        _order = session.query(GoodsOrder).filter_by(**_filter).one()
        if not _order:
            session.close()
            logger.error(f"确认收货: 订单不存在！ order_id={order_id}")
            return self.finish(ret_msg(-1, error_message="确认收货失败"))

        if not add_mq_task(
            order_id,
            message_type=3,
            delay=DAYS_AFTER_RECEIVED_FOR_AUTO_COMPLETION * 24 * 3600,
        ):
            session.close()
            return self.finish(ret_msg(-1, error_message="确认收货失败"))

        _order.sdef_order_status = OrderStatus.RECEIVED
        session.commit()
        session.close()
        return self.finish(ret_msg())


class AutoReceived(BaseHandler):
    async def get(self, order_id):
        """
        订单自动确认收货
        """
        logger.info("调用自动确认收货接口：order_id=%s,ip=%s" % (order_id, self.request.remote_ip))

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        _filter = dict(
            sdef_order_id=order_id,
        )
        order = session.query(GoodsOrder).filter_by(**_filter).one()
        if not order:
            session.close()
            logger.error(f"自动收货: 订单不存在！ order_id={order_id}")
            return self.finish(ret_msg(-1, error_message="发货失败"))

        if not add_mq_task(
            order_id,
            message_type=4,
            delay=DAYS_AFTER_SHIPPED_FOR_AUTO_COMPLETION * 24 * 3600,
        ):
            session.close()
            return self.finish(ret_msg(-1, error_message="发货失败"))
        session.close()
        return self.finish(ret_msg())


class Income(BaseHandler):
    def get(self, order_id):
        logger.info("调用收益计算接口：order_id=%s,ip=%s" % (order_id, self.request.remote_ip))
        # future = await gen.Task(tasks.calculate_benefit.apply_async, args=[order_id])
        # ret = future.result
        # return self.finish(ret)
        from helper.payment import pay_util

        ret = pay_util.calculate_benefit(order_id)
        return self.finish(json.dumps(ret))


class Refund(BaseHandler):
    def post(self):
        cipher_text = self.request.body.decode("utf-8")
        refund_instance = CancelOrderRefund(cipher_text)
        if order_refund(refund_instance):
            ret = ret_msg()
        else:
            ret = ret_msg(-1, error_message="退款失败，请联系管理员")
        return self.finish(ret)


class UpdateUser(BaseHandler):
    async def get(self, open_id):
        url = "https://api.weixin.qq.com/cgi-bin/user/info"
        access_token = self.get_access_token()
        params = dict(
            access_token=access_token,
            openid=open_id,
            lang="zh_CN",
        )
        response = requests.get(url=url, params=params, timeout=30)
        logger.debug(response.text)
        user_dict = response.json()
        if user_dict.get("subscribe") == 0:
            return self.write(ret_msg(-1, error_message="未关注公众号"))

        if not UserHelper.update_user(user_dict):
            return self.write(ret_msg(-1, error_message="更新失败"))

        return self.write(ret_msg())


class BindUser(BaseHandler):
    async def get(self, agency_uid):
        open_id = await self.get_open_id()
        if not (open_id and not re.match(r"^\d+$", open_id)):
            context = dict(
                page_title="消息",
                title="操作失败",
                description="openid错误",
            )
            return self.render_html("error.html", **context)

        class User(object):
            pass

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_user", "model": User},
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )
        user = session.query(User).filter_by(ebf_user_id=open_id).first()
        if not user:
            # 用户不存在时创建用户(属于默认合伙人)
            await self.create_user(open_id, DEFAULT_AGENCY_UID)

        # 检查合伙人是否存在
        agency = (
            session.query(Agency)
            .filter_by(ebf_factory_id=FACTORY_ID, ebf_agency_uid=agency_uid)
            .first()
        )
        if not agency:
            context = dict(
                page_title="消息",
                title="操作失败",
                description="合伙人不存在",
            )
            session.close()
            return self.render_html("error.html", **context)

        user_agency = (
            session.query(UserAgency)
            .filter_by(ebf_agency_id=agency.ebf_agency_id, ebf_ua_bind_user_id=None)
            .first()
        )
        if not user_agency:
            context = dict(
                page_title="消息",
                title="操作失败",
                description="已被绑定或未开通帐号",
            )
            session.close()
            return self.render_html("error.html", **context)

        user_agency.ebf_ua_bind_user_id = open_id
        session.commit()

        context = dict(
            page_title="消息",
            title="操作成功",
            description="您已经绑定了云后台账户",
        )
        session.close()
        return self.render_html("success.html", **context)


class UserAccount(BaseHandler):
    async def get(self):
        open_id = await self.get_open_id()

        # return self.redirect("/static/app1/index.html#/personal")
        # 直接跳转个人中心，再从个人中心进入商家后台。 以下代码无效

        class Agency(object):
            pass

        class UserAgency(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "ebt_agency", "model": Agency},
                {"db_table": "ebt_user_agency", "model": UserAgency},
            ]
        )

        ua = session.query(UserAgency).filter_by(ebf_ua_bind_user_id=open_id).first()

        if ua:
            agency = (
                session.query(Agency).filter_by(ebf_agency_id=ua.ebf_agency_id).first()
            )
            if agency:
                agency_id = agency.ebf_agency_id
                agency_type = agency.ebf_agency_type
                agency_sub_type = agency.ebf_agency_sub_type
                if agency_type == AgencyType.STORE:
                    if agency_sub_type == 0:
                        # 线下门店：商家和店员后台
                        return self.redirect("/static/storebackstage/index.html#/index")
                    else:
                        # 线上门店后台
                        return self.redirect("/static/admin/index.html#/index")
                elif agency_type == AgencyType.CLERK:
                    parent_agency_id = agency.ebf_agency_parent_id
                    parent_agency = UserHelper.get_agency(parent_agency_id)
                    parent_agency_type = parent_agency.ebf_agency_type
                    parent_agency_sub_type = parent_agency.ebf_agency_sub_type
                    if parent_agency_type == AgencyType.STORE:
                        if parent_agency_sub_type == 0:
                            # 线下门店店员
                            return self.redirect(
                                "/static/storebackstage/index.html#/index"
                            )
                        else:
                            # 线上门店店员
                            return self.redirect("/static/admin/index.html#/index")
                    elif parent_agency_type == AgencyType.SUPPLIER:
                        # 供应商职员
                        return self.redirect("/static/admin/index.html#/indexSr")
                    else:
                        logger.error(
                            f"店员账号异常 agency_id={agency_id} parent_agency_type={parent_agency_type}"
                        )
                        # 按普通用户处理
                        return self.redirect("/static/app1/index.html#/personal")
                elif agency_type == AgencyType.SUPPLIER:
                    # 供应商账号
                    return self.redirect("/static/admin/index.html#/indexSr")
                else:
                    # 合伙人后台
                    return self.redirect("/static/partners3/index.html#/newHome")
            else:
                # 合伙人记录不存在
                logger.error(f"合伙人记录不存在! open_id={open_id}")
                # 按普通用户处理
                return self.redirect("/static/app1/index.html#/personal")
        # 普通用户
        return self.redirect("/static/app1/index.html#/personal")

        # 屏端商城旧页面
        # user = session.query(User).filter_by(ebf_user_id=open_id).first()
        # account_money = session.query(AccountMoney).filter_by(ebf_am_user_id=open_id).first()
        # balance = Decimal("0")
        # if account_money:
        #     balance = Decimal("0") if account_money.ebf_am_is_forbid else account_money.ebf_am_money
        #
        # context = dict(
        #     username=user.ebf_user_id,
        #     nickname=user.ebf_user_nickname,
        #     head=user.ebf_user_headurl,
        #     text="我的账户",
        #     open_id=open_id,
        #     account_money=balance,
        #     is_bind_agency=is_bind_agency,
        # )
        #
        # template = "mall/account.html"
        # session.close()
        # return self.render_html(template, **context)


class Order(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        open_id = await self.get_open_id()
        is_pad = True if re.match(r"^\d+$", open_id) else False
        order_type = self.get_argument("t", None)

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        filters = dict(
            sdef_order_is_delete=0,
        )
        if is_pad:
            filters["sdef_order_describe"] = open_id
        else:
            filters["sdef_order_device_id"] = open_id

        if order_type:
            order_type = int(order_type)
            filters["sdef_order_status"] = order_type
        _order_array = (
            session.query(GoodsOrder)
            .filter_by(**filters)
            .filter(GoodsOrder.sdef_order_type.in_([1, 2]))
            .order_by(GoodsOrder.sdef_order_id.desc())
            .all()
        )
        order_array = []
        for o in _order_array:
            if o.sdef_order_status == OrderStatus.WAIT_PAY:
                _status = "待支付"
            elif o.sdef_order_status == OrderStatus.WAIT_EXPRESS:
                _status = "待发货"
            elif o.sdef_order_status == OrderStatus.WAIT_PICKUP:
                _status = "待发货"
            elif o.sdef_order_status == OrderStatus.EXPRESSED:
                _status = "已发货"
            elif o.sdef_order_status == OrderStatus.CHECK:
                _status = "审核中"
            elif o.sdef_order_status == OrderStatus.COMPLETE:
                _status = "完成"
            elif o.sdef_order_status == OrderStatus.INVALID:
                _status = "失效"
            elif o.sdef_order_status == OrderStatus.REFUND:
                _status = "已退款"
            else:
                _status = "未知"
            if o.sdef_order_pay_status == PayStatus.REFUND:
                _status = "已退款"

            price_total = Decimal(0)
            cart_goods = json.loads(o.sdef_order_goods)
            for c in cart_goods:
                price_total += Decimal(c["goods_price"]) * Decimal(c["count"])

            order_array.append(
                dict(
                    order_id=o.sdef_order_id,
                    status=_status,
                    cart_goods=cart_goods,
                    goods_count=len(cart_goods),
                    price_total=o.sdef_order_fee + o.sdef_order_balance_fee,
                    per_order_type=o.sdef_order_type,
                )
            )
            pass
        context = dict(
            text="订单查询",
            order_array=order_array,
            order_type=order_type,
            open_id=open_id,
            device_id=open_id,
        )
        # session.close()

        template = "pad_mall/order.html" if is_pad else "mall/order.html"
        return self.render_html(template, **context)


class OrderDetail(BaseHandler):
    async def get(self, order_id):
        open_id = await self.get_open_id()

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        class UserAddress(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_goods", "model": Goods},
                {"db_table": "sdet_address", "model": UserAddress},
            ]
        )

        filters = dict(
            sdef_order_id=order_id,
        )
        # 允许公司账号查看订单
        if open_id not in config.COMMON_NOTICE_RECEIVER:
            device_id = self.get_argument("device_id", None)
            if device_id:
                filters["sdef_order_describe"] = open_id
            else:
                filters["sdef_order_device_id"] = open_id

        o = (
            session.query(GoodsOrder)
            .filter_by(**filters)
            .order_by(GoodsOrder.sdef_order_id.desc())
            .first()
        )
        if o.sdef_order_status == 1:
            _status = "待支付"
        elif o.sdef_order_status == 2:
            _status = "待发货"
        elif o.sdef_order_status == 3:
            _status = "已发货"
        elif o.sdef_order_status == 31:
            _status = "审核中"
        elif o.sdef_order_status == 4:
            _status = "完成"
        elif o.sdef_order_status == 5:
            _status = "失效"
        elif o.sdef_order_status == 6:
            _status = "已退款"
        else:
            _status = "未知"

        if o.sdef_order_pay_status == 1:
            pay_status = "已支付"
        elif o.sdef_order_pay_status == 2:
            pay_status = "已退款"
        elif o.sdef_order_pay_status == 0:
            pay_status = "未支付"
        else:
            pay_status = "未知"

        cart_goods = json.loads(o.sdef_order_goods)
        order_express_no = []
        try:
            if o.sdef_order_express_no:
                order_express_no = json.loads(o.sdef_order_express_no)
                if len(order_express_no) > 0:
                    express_no_item = order_express_no[0]
                    if isinstance(express_no_item, dict):
                        order_express_no = [
                            express_no_item.get("express_number")
                            + " 【%s】" % express_no_item.get("express_name")
                        ]
        except Exception as e:
            logger.exception(e)

        encrypt_order_id = GiftHelper.encrypt_order_id(o.sdef_order_id)
        address = (
            session.query(UserAddress)
            .filter_by(sdef_address_id=o.sdef_order_address_id)
            .first()
        )

        host = self.request.host
        protocol = self.request.protocol
        gift_full_url = protocol + "://" + host + "/gift/" + encrypt_order_id
        is_wechat = self.is_in_wechat()
        context = dict(
            title="订单详情",
            is_wechat=is_wechat,
            status=_status,
            pay_status=pay_status,
            order_id=o.sdef_order_id,
            order_express_no=order_express_no,
            delivery_fee=o.sdef_order_delivery_fee,
            cart_goods=cart_goods,
            create_time=o.sdef_order_create_time,
            order_fee=o.sdef_order_fee + o.sdef_order_balance_fee,
            balance_fee=o.sdef_order_balance_fee,
            goods_count=len(cart_goods),
            address=address,
            per_order_type=o.sdef_order_type,
            message=o.sdef_order_message,
            gift_full_url=gift_full_url,
        )
        # session.close()

        if is_wechat:
            app_id = MP_APP_ID
            time_stamp = int(str(time.time()).split(".")[0])
            nonce_str = WechatPay.generate_nonce_str()

            host = self.request.host
            url_params = self.request.query
            request_path = self.request.path
            protocol = self.request.protocol
            full_url = protocol + "://" + host + request_path
            if url_params:
                full_url += "?" + url_params

            jsapi_ticket = self.get_jsapi_ticket()
            signature = Wechat_Base.signature(
                nonce_str, time_stamp, full_url, jsapi_ticket
            )
            logging.debug("signature：%s" % signature)
            context["app_id"] = app_id
            context["time_stamp"] = time_stamp
            context["nonce_str"] = nonce_str
            context["signature"] = signature

        return self.render_html("mall/order-detail.html", **context)

    async def post(self, order_id):
        open_id = await self.get_open_id()

        class GoodsOrder(object):
            pass

        class Goods(object):
            pass

        session = self.get_db_session(
            [
                {"db_table": "sdet_order", "model": GoodsOrder},
                {"db_table": "sdet_goods", "model": Goods},
            ]
        )
        device_id = self.get_argument("device_id", None)
        action = self.get_argument("action", None)
        _filter = dict(
            sdef_order_id=order_id,
        )
        if device_id:
            _filter["sdef_order_describe"] = device_id
        else:
            _filter["sdef_order_device_id"] = open_id
        _order = session.query(GoodsOrder).filter_by(**_filter).first()
        if not _order:
            session.close()
            logger.error(
                f"订单不存在 open_id={open_id}, order_id={order_id}, action={action}"
            )
            return self.finish(ret_msg(-1, error_message="订单不存在"))

        if action == "cancel":
            # todo 已支付未发货的订单也能取消，取消后退款并且返还抵扣的余额
            if _order.sdef_order_status not in [
                OrderStatus.WAIT_PAY,
                OrderStatus.WAIT_EXPRESS,
                OrderStatus.WAIT_PICKUP,
            ]:
                ret = ret_msg(-1, error_message="只有待支付、待发货的订单才能取消")
                session.close()
                return self.finish(ret)

            if _order.sdef_order_status == OrderStatus.WAIT_PAY:
                _order.sdef_order_status = OrderStatus.INVALID
                _order.sdef_order_is_delete = 1
                _order.sdef_order_delete_time = datetime.datetime.now()
                # 增加库存
                order_goods = json.loads(_order.sdef_order_goods)
                for g in order_goods:
                    goods = (
                        session.query(Goods).filter_by(sdef_goods_id=g["id"]).first()
                    )
                    if goods:
                        goods.sdef_goods_count += int(g["count"])
                session.commit()
            elif (
                _order.sdef_order_status == OrderStatus.WAIT_EXPRESS
                or _order.sdef_order_status == OrderStatus.WAIT_PICKUP
            ):
                # 已支付的订单取消
                _order.sdef_order_status = OrderStatus.CHECK
                session.commit()
                logger.info(
                    "订单状态修改成功：order_id=%s,是否审核退款=%s"
                    % (order_id, CANCEL_PAID_ORDER_IS_NEED_CHECK)
                )
                if not CANCEL_PAID_ORDER_IS_NEED_CHECK:
                    cancel_order_immediate_refund(order_id)
            session.close()
            return self.finish(ret_msg())
        elif action == "confirm":
            if _order.sdef_order_status != 3:
                ret = ret_msg(-1, error_message="只有已发货的订单才能确认收货")
                session.close()
                return self.finish(ret)

            if (
                _order.sdef_order_type == OrderType.GIFT
                and not _order.sdef_order_address_id
            ):
                ret = ret_msg(-1, error_message="此礼品订单未填写收货地址")
                session.close()
                return self.finish(ret)

            # ret_dict = calculate_benefit(order_id)
            # # 返回的消息为None
            # logger.debug(ret_dict)
            # if ret_dict["code"] != 0:
            #     return self.finish(json.dumps(ret_dict))
            if not add_mq_task(
                order_id,
                message_type=3,
                delay=DAYS_AFTER_RECEIVED_FOR_AUTO_COMPLETION * 24 * 3600,
            ):
                session.close()
                return self.finish(ret_msg(-1, error_message="确认收货失败"))

            _order.sdef_order_status = OrderStatus.RECEIVED
            session.commit()
            session.close()
            return self.finish(ret_msg())

        elif action == "get-express":
            try:
                if _order.sdef_order_express_no:
                    express_no = json.loads(_order.sdef_order_express_no)
                    if len(express_no) <= 0:
                        session.close()
                        raise Exception("没有物流信息:order_id=%s" % order_id)

                    express_no_item = express_no[0]
                    if not isinstance(express_no_item, dict):
                        logger.debug(express_no_item)
                        session.close()
                        raise Exception("物流信息格式不对:order_id=%s" % order_id)

                    express_symbol = express_no_item.get("express_symbol")
                    express_number = express_no_item.get("express_number")
                    # 使用tornado的异步查询
                    http = httpclient.AsyncHTTPClient()

                    url = "https://poll.kuaidi100.com/poll/query.do"
                    param = (
                        '{"com":"'
                        + express_symbol.lower()
                        + '","num":"'
                        + express_number
                        + '"}'
                    )
                    s = ExpressHelper.sign(param)
                    data = dict(
                        customer=KUAIDI100_CUSTOMER, sign=s, param=param
                    )
                    logger.debug("params=%s" % data)
                    url = url_concat(url, data)
                    request = HTTPRequest(
                        url, body=json_encode(data), method="POST", validate_cert=False
                    )
                    logger.debug("异步请求开始")
                    result = await http.fetch(request)
                    r = result.body.decode()
                    obj = json.loads(r)
                    if obj.get("message") != "ok":
                        ret = ret_msg(-1)
                    else:
                        ret = ret_msg(data=obj.get("data"))
                    self.finish(ret)
                    logger.debug("异步请求挂起，执行其它任务")
                    session.close()
            except Exception as e:
                logger.exception(e)
                session.close()


class Share(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        """
        打开分享页的链接：/share?oid=xxx
        url_param: oid 推荐人的open_id
        """

        is_wechat = self.is_in_wechat()

        owner_open_id = self.get_argument("oid", None)
        open_id = None
        description = "我的二维码"
        try:
            if is_wechat:
                # 在微信打开的直接进行页面跳转
                open_id = await self.get_open_id()
                logger.debug(
                    "打开分享页面：owner_open_id=%s,open_id=%s" % (owner_open_id, open_id)
                )
                await self.bind_user(open_id)

                if not owner_open_id:
                    raise ShareNotOwnerException("owner_open_id为空")

                # 跳转到分享者的分享页面，帮助分享者继续传播
                return self.redirect("/shared?oid=" + owner_open_id)
            else:
                # 非微信中打开
                if not owner_open_id:
                    context = dict(
                        title="错误",
                        description="分享地址错误",
                    )
                    return self.render_html("error.html", **context)

                description = "思达尔智能酒柜，让你的生活更精彩 ！"
                open_id = owner_open_id
        except ShareNotOwnerException:
            logger.debug("打开自己的分享页：openid=%s" % open_id)
        except Exception as e:
            logger.exception(e)

        url = self.get_argument("url", None)
        if url:
            self.redirect(url)
            return

        context = dict(
            text="分享",
            description=description,
            owner_open_id=owner_open_id,
            open_id=open_id,
            is_wechat=is_wechat,
        )
        if is_wechat:
            app_id = MP_APP_ID
            time_stamp = int(str(time.time()).split(".")[0])
            nonce_str = WechatPay.generate_nonce_str()

            host = self.request.host
            url_params = self.request.query
            request_path = self.request.path
            protocol = self.request.protocol
            full_url = protocol + "://" + host + request_path
            if url_params:
                full_url += "?" + url_params

            jsapi_ticket = self.get_jsapi_ticket()
            signature = Wechat_Base.signature(
                nonce_str, time_stamp, full_url, jsapi_ticket
            )
            logging.debug("signature：%s" % signature)
            context["app_id"] = app_id
            context["protocol"] = protocol
            context["time_stamp"] = time_stamp
            context["nonce_str"] = nonce_str
            context["signature"] = signature

        return self.render_html("mall/share.html", **context)


class Shared(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        """
        分享后的跳转链接：/shared?oid=xxx&url=https://xxx
        url_param: oid 推荐人的open_id
        url_param: url 处理分享逻辑后最终跳转的链接
        """

        open_id = await self.get_open_id()
        await self.bind_user(open_id)

        url = self.get_argument("url", None)
        if url:
            self.redirect(url)
            return

        # 改为跳转前端页面
        # return self.redirect("/static/share/user/shared.html")

        is_wechat = self.is_in_wechat()
        context = dict(
            text="分享",
            open_id=open_id,
            is_wechat=is_wechat,
        )

        if is_wechat:
            app_id = MP_APP_ID
            time_stamp = int(str(time.time()).split(".")[0])
            nonce_str = WechatPay.generate_nonce_str()

            host = self.request.host
            url_params = self.request.query
            request_path = self.request.path
            protocol = self.request.protocol
            full_url = protocol + "://" + host + request_path
            if url_params:
                full_url += "?" + url_params

            jsapi_ticket = self.get_jsapi_ticket()
            signature = Wechat_Base.signature(
                nonce_str, time_stamp, full_url, jsapi_ticket
            )
            logging.debug("signature：%s" % signature)
            context["app_id"] = app_id
            context["protocol"] = protocol
            context["time_stamp"] = time_stamp
            context["nonce_str"] = nonce_str
            context["signature"] = signature

        return self.render_html("mall/shared.html", **context)


class Gift(BaseHandler):
    def data_received(self, chunk):
        pass

    def get(self, order_id):
        decrypt_order_id = GiftHelper.decrypt_order_id(order_id)
        # code 没问题时允许填写地址
        ret = GiftHelper.check_order(decrypt_order_id)
        if ret.get("code") != 0:
            context = dict(
                title="提示",
                description=ret.get("msg"),
            )
            return self.render_html("error.html", **context)

        context = dict(
            titile="有人给你送礼了，请填写收货信息！",
            order_id=decrypt_order_id,
            code=order_id,
        )
        return self.render_html("mall/gift.html", **context)


class Go(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        # 中转页调用微信登录
        open_id = await self.get_open_id()
        self.bind_user(open_id)

        url = self.get_argument("url", None)
        # 针对vue-router hash 模式做微信兼容处理
        if url:
            decoded_url = parse.unquote(url)
            return self.redirect(decoded_url)
        else:
            return self.redirect("/404")


class InvitePartner(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self, agency_type, parent_open_id):
        open_id = await self.get_open_id()
        self.bind_user(open_id)
        if open_id:
            # 邀请初级合伙人
            if agency_type == "0":
                return self.redirect(
                    "/static/partners3/index.html#/partnerEnter/0/%s" % parent_open_id
                )  # 重定向地址待定
            # 邀请高级合伙人
            elif agency_type == "1":
                # return self.redirect("/static/register/index.html#/wineryRegister/1/%s" % parent_open_id)
                return self.redirect(
                    "/static/register/index.html#/junpart?oid=%s" % parent_open_id
                )
            # 邀请初级事业合伙人
            elif agency_type == "2":
                return self.redirect(
                    "/static/register/index.html#/careerPartnerRegister/2/%s"
                    % parent_open_id
                )
            # 邀请商家
            elif agency_type == "3":
                return self.redirect(
                    "/static/register/index.html#/register/3/%s" % parent_open_id
                )
            # 邀请店员
            elif agency_type == "4":
                return self.redirect(
                    "/static/register/index.html#/register/4/%s" % parent_open_id
                )
            # 邀请商家推荐人
            elif agency_type == "5":
                return self.redirect(
                    "/static/register/index.html#/register/5/%s" % parent_open_id
                )
            # 邀请私人酒庄
            elif agency_type == "6":
                return self.redirect(
                    "/static/register/index.html#/wineryRegister/6/%s" % parent_open_id
                )
            elif agency_type == "201801":
                return self.redirect(
                    "/static/partners/index.html#/partnerAdd?oid=%s&promotion=%s"
                    % (parent_open_id, agency_type)
                )
            else:
                context = dict(
                    title="邀请合伙人类型参数错误",
                    description="合伙人类型参数错误：未知邀请合伙人类型",
                )
                return self.render_html("error.html", **context)
        else:
            context = dict(
                title="请用微信识别二维码",
                description="请用微信识别二维码，确认关注登录公众号",
            )
            return self.render_html("error.html", **context)


class Promotion(BaseHandler):
    def data_received(self, chunk):
        pass

    async def get(self):
        """
        新用户活动中转页
        根据是否参与了活动跳转到不同的页面
        :param:
        :return:
        """
        open_id = await self.get_open_id()
        await self.bind_user(open_id)
        if open_id:
            result = UserHelper.is_buy_wine(open_id)
            if result:
                return self.redirect(
                    "/static/share/user/regular-client.html?v=20180514"
                )
        return self.redirect("/static/share/user/new-client.html?v=20180514")
